/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl; import org.everrest.core.ApplicationContext; import org.everrest.core.DependencySupplier; import org.everrest.core.FieldInjector; import org.everrest.core.Parameter; import org.everrest.core.impl.method.ParameterResolver; import org.everrest.core.impl.method.ParameterResolverFactory; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentMatcher; import javax.ws.rs.CookieParam; import javax.ws.rs.DefaultValue; import javax.ws.rs.Encoded; import javax.ws.rs.HeaderParam; import javax.ws.rs.MatrixParam; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.Response; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static javax.ws.rs.core.Response.Status.NOT_FOUND; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class FieldInjectorImplTest { @Rule public ExpectedException thrown = ExpectedException.none(); private ParameterResolverFactory parameterResolverFactory; private ParameterResolver<PathParam> pathParameterResolver; private ParameterResolver<QueryParam> queryParameterResolver; private ParameterResolver<MatrixParam> matrixParameterResolver; private ParameterResolver<CookieParam> cookieParameterResolver; private ParameterResolver<HeaderParam> headerParameterResolver; private ApplicationContext applicationContext; private DependencySupplier dependencySupplier; @Before public void setUp() throws Exception { mockApplicationContext(); mockParameterResolverFactory(); } private void mockApplicationContext() { dependencySupplier = mock(DependencySupplier.class); applicationContext = mock(ApplicationContext.class); when(applicationContext.getQueryParameters()).thenReturn(new MultivaluedHashMap<>()); when(applicationContext.getDependencySupplier()).thenReturn(dependencySupplier); ApplicationContext.setCurrent(applicationContext); } @SuppressWarnings("unchecked") private void mockParameterResolverFactory() { parameterResolverFactory = mock(ParameterResolverFactory.class); pathParameterResolver = mock(ParameterResolver.class); queryParameterResolver = mock(ParameterResolver.class); matrixParameterResolver = mock(ParameterResolver.class); cookieParameterResolver = mock(ParameterResolver.class); headerParameterResolver = mock(ParameterResolver.class); when(parameterResolverFactory.createParameterResolver(isA(PathParam.class))).thenReturn(pathParameterResolver); when(parameterResolverFactory.createParameterResolver(isA(QueryParam.class))).thenReturn(queryParameterResolver); when(parameterResolverFactory.createParameterResolver(isA(MatrixParam.class))).thenReturn(matrixParameterResolver); when(parameterResolverFactory.createParameterResolver(isA(CookieParam.class))).thenReturn(cookieParameterResolver); when(parameterResolverFactory.createParameterResolver(isA(HeaderParam.class))).thenReturn(headerParameterResolver); } @Test public void createsFieldInjectorForField() throws Exception { FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("pathParam"), parameterResolverFactory); assertEquals("pathParam", fieldInjector.getName()); assertEquals(PathParam.class, fieldInjector.getAnnotation().annotationType()); assertEquals(String.class, fieldInjector.getParameterClass()); assertEquals(1, fieldInjector.getAnnotations().length); assertNull(fieldInjector.getDefaultValue()); assertFalse(fieldInjector.isEncoded()); } @Test public void createsFieldInjectorForEncodedField() throws Exception { FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("queryParam"), parameterResolverFactory); assertEquals("queryParam", fieldInjector.getName()); assertEquals(QueryParam.class, fieldInjector.getAnnotation().annotationType()); assertEquals(String.class, fieldInjector.getParameterClass()); assertEquals(2, fieldInjector.getAnnotations().length); assertNull(fieldInjector.getDefaultValue()); assertTrue(fieldInjector.isEncoded()); } @Test public void createsFieldInjectorForFieldWIthDefaultValue() throws Exception { FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("headerParam"), parameterResolverFactory); assertEquals("headerParam", fieldInjector.getName()); assertEquals(HeaderParam.class, fieldInjector.getAnnotation().annotationType()); assertEquals(String.class, fieldInjector.getParameterClass()); assertEquals(2, fieldInjector.getAnnotations().length); assertEquals("default", fieldInjector.getDefaultValue()); assertFalse(fieldInjector.isEncoded()); } @Test public void injectsField() throws Exception { when(pathParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenReturn("path parameter"); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("pathParam"), parameterResolverFactory); Resource instance = new Resource(); fieldInjector.inject(instance, applicationContext); assertEquals("path parameter", instance.pathParam); } @Test public void usesSetterForSettingField() throws Exception { when(headerParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenReturn("header parameter"); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("headerParam"), parameterResolverFactory); Resource instance = spy(new Resource()); fieldInjector.inject(instance, applicationContext); assertEquals("header parameter", instance.headerParam); verify(instance).setHeaderParam("header parameter"); } @Test public void injectsExternalDependencyToField() throws Exception { Dependency dependency = new Dependency(); when(dependencySupplier.getInstance(argThat(new ArgumentMatcher<ConstructorParameter>() { @Override public boolean matches(Object argument) { return ((FieldInjector)argument).getParameterClass() == Dependency.class; } }))).thenReturn(dependency); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("dependency"), parameterResolverFactory); Resource instance = new Resource(); fieldInjector.inject(instance, applicationContext); assertSame(dependency, instance.dependency); } @Test public void throwsWebApplicationExceptionWithStatus_NOT_FOUND_WhenFieldAnnotatedWithPathParamAnnotationCanNotBeResolved() throws Exception { when(pathParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenThrow(new Exception()); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("pathParam"), parameterResolverFactory); Resource instance = new Resource(); thrown.expect(webApplicationExceptionWithStatusMatcher(NOT_FOUND)); fieldInjector.inject(instance, applicationContext); } @Test public void throwsWebApplicationExceptionWithStatus_NOT_FOUND_WhenFieldAnnotatedWithQueryParamAnnotationCanNotBeResolved() throws Exception { when(queryParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenThrow(new Exception()); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("queryParam"), parameterResolverFactory); Resource instance = new Resource(); thrown.expect(webApplicationExceptionWithStatusMatcher(NOT_FOUND)); fieldInjector.inject(instance, applicationContext); } @Test public void throwsWebApplicationExceptionWithStatus_NOT_FOUND_WhenFieldAnnotatedWithMatrixParamAnnotationCanNotBeResolved() throws Exception { when(matrixParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenThrow(new Exception()); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("matrixParam"), parameterResolverFactory); Resource instance = new Resource(); thrown.expect(webApplicationExceptionWithStatusMatcher(NOT_FOUND)); fieldInjector.inject(instance, applicationContext); } @Test public void throwsWebApplicationExceptionWithStatus_BAD_REQUEST_WhenFieldAnnotatedWithHeaderParamAnnotationCanNotBeResolved() throws Exception { when(headerParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenThrow(new Exception()); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("headerParam"), parameterResolverFactory); Resource instance = new Resource(); thrown.expect(webApplicationExceptionWithStatusMatcher(BAD_REQUEST)); fieldInjector.inject(instance, applicationContext); } @Test public void throwsWebApplicationExceptionWithStatus_BAD_REQUEST_WhenFieldAnnotatedWithCookieParamAnnotationCanNotBeResolved() throws Exception { when(cookieParameterResolver.resolve(isA(Parameter.class), eq(applicationContext))).thenThrow(new Exception()); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("cookieParam"), parameterResolverFactory); Resource instance = new Resource(); thrown.expect(webApplicationExceptionWithStatusMatcher(BAD_REQUEST)); fieldInjector.inject(instance, applicationContext); } @Test public void throwsWebApplicationExceptionWithStatus_INTERNAL_SERVER_ERROR_WhenNotAnnotatedFieldCanNotBeResolved() throws Exception { when(dependencySupplier.getInstance(argThat(new ArgumentMatcher<ConstructorParameter>() { @Override public boolean matches(Object argument) { return ((FieldInjector)argument).getParameterClass() == Dependency.class; } }))).thenThrow(new RuntimeException()); FieldInjectorImpl fieldInjector = new FieldInjectorImpl(Resource.class.getDeclaredField("dependency"), parameterResolverFactory); Resource instance = new Resource(); thrown.expect(webApplicationExceptionWithStatusMatcher(INTERNAL_SERVER_ERROR)); fieldInjector.inject(instance, applicationContext); } @Test public void throwsRuntimeExceptionWhenFieldHasTwoTypesOfAnnotation() throws Exception { thrown.expect(RuntimeException.class); new FieldInjectorImpl(InvalidResource.class.getDeclaredField("pathParam"), parameterResolverFactory); } private BaseMatcher<Throwable> webApplicationExceptionWithStatusMatcher(Response.Status status) { return new BaseMatcher<Throwable>() { @Override public boolean matches(Object item) { return item instanceof WebApplicationException && status.equals(((WebApplicationException)item).getResponse().getStatusInfo()); } @Override public void describeTo(Description description) { description.appendText(String.format("WebApplicationException with status %d \"%s\"", status.getStatusCode(), status.getReasonPhrase())); } }; } @Path("/a/{x}") public static class Resource { @PathParam("x") private String pathParam; @Encoded @QueryParam("q") private String queryParam; @MatrixParam("m") private String matrixParam; @CookieParam("c") private String cookieParam; @DefaultValue("default") @HeaderParam("h") private String headerParam; public void setHeaderParam(String headerParam) { this.headerParam = headerParam; } private Dependency dependency; } @Path("/a/{x}") public static class InvalidResource { @PathParam("x") @HeaderParam("h") private String pathParam; } public static class Dependency { } }